#include "wizardnewproject.h"
#include "dlgedittask.h"
#include "dlgedittag.h"
#include "pm/manager.h"
#include "pm/project.h"
#include "pm/workrequest.h"
#include "pm/taskhistory.h"
#include "main.h"
#include <wx/msgdlg.h>
#include <boost/foreach.hpp>

#include "res/calculator64.xpm"

////////////////////////////////////////////////////////////////////////////////
// WizardNewProject
////////////////////////////////////////////////////////////////////////////////

WizardNewProject::WizardNewProject(wxWindow* parent)
: wxWizard(parent, wxID_ANY, _("New project wizard"), wxBitmap(calculator64_xpm), wxDefaultPosition, wxDEFAULT_DIALOG_STYLE|wxRESIZE_BORDER)
{
	// switch to memory database
	m_oldFilename = pm::get_db_name();
	pm::load(pm::Manager::MEMORY);
	pm::clear_all();

	// Create initials project and work request
	pm::Project project;
	project.name(wxEmptyString);
	pm::insert(project);
	pm::WorkRequest wr;
	wr.name(wxEmptyString);
	wr.date(wxDateTime::Today());
	wr.id_project(1);
	pm::insert(wr);
	
	m_page1 = new wxWizardPageSimple(this);
	m_panelName = new WizardPageProjectName(m_page1);
	SetPagePanel(m_page1, m_panelName);
	
	wxWizardPageSimple* page2 = new wxWizardPageSimple(this);
	m_panelWorkRequest = new WizardPageWorkRequest(page2);
	SetPagePanel(page2, m_panelWorkRequest);
	wxWizardPageSimple::Chain(m_page1, page2);
	
	wxWizardPageSimple* page3 = new wxWizardPageSimple(this);
	m_panelTags = new WizardPageTags(page3);
	SetPagePanel(page3, m_panelTags);
	wxWizardPageSimple::Chain(page2, page3);

	wxWizardPageSimple* page4 = new wxWizardPageSimple(this);
	m_panelTasks = new WizardPageTasks(page4);
	SetPagePanel(page4, m_panelTasks);
	wxWizardPageSimple::Chain(page3, page4);

	GetPageAreaSizer()->Add(m_page1);
	
	Connect(wxEVT_WIZARD_CANCEL,   wxWizardEventHandler(WizardNewProject::OnCancel),   NULL, this);
	Connect(wxEVT_WIZARD_CANCEL,   wxWizardEventHandler(WizardNewProject::OnCancel),   NULL, this);
	Connect(wxEVT_WIZARD_FINISHED, wxWizardEventHandler(WizardNewProject::OnFinished), NULL, this);
}

void WizardNewProject::SetPagePanel(wxWizardPage* page, wxPanel* panel)
{
	page->SetExtraStyle(wxWS_EX_VALIDATE_RECURSIVELY);
	wxBoxSizer* sizer = new wxBoxSizer(wxVERTICAL);
	sizer->Add(panel, 1, wxEXPAND|wxALL, 5);
	page->SetSizer(sizer);
	page->Layout();
	sizer->Fit(page);
}

void WizardNewProject::OnCancel(wxWizardEvent& WXUNUSED(event))
{
	pm::load(m_oldFilename);
}

void WizardNewProject::OnPageChanged(wxWizardEvent& event)
{
}

void WizardNewProject::OnFinished(wxWizardEvent& WXUNUSED(event) )
{
	// create project database
	m_filename = m_panelName->GetFileName();
	if (wxFileExists(m_filename)) {
		wxRemoveFile(m_filename);
	}
	
	// Create initial tasks
	pm::ListTask tasks;
	m_panelTasks->GetTasks(tasks);
	BOOST_FOREACH (const pm::Task task, tasks) {
		pm::CreateInitialTaskHistory critCreateInitialTask(task);
		pm::query(critCreateInitialTask);
	}
	
	// Backup memory to file
	pm::backup(m_filename);
	
	// And load the backup file 
	if (pm::load(m_filename) == false) {
		wxMessageBox(_("Can't load database file"), _("New project"), wxOK|wxICON_ERROR);
		pm::load(m_oldFilename);
		EndModal(wxID_CANCEL);
		return;
	}
	
	// Inform everybody that the project has been loaded
	wxCommandEvent evt(pmEVT_PROJECT_LOADED);
	evt.SetInt(1);
	wxPostEvent(wxTheApp, evt);
}


////////////////////////////////////////////////////////////////////////////////
// WizardPageProjectName
////////////////////////////////////////////////////////////////////////////////

WizardPageProjectName::WizardPageProjectName(wxWindow* parent)
: WizardPageProjectNameGui(parent)
{
}

bool WizardPageProjectName::TransferDataFromWindow()
{
	if (wxPanel::TransferDataFromWindow() == false) {
		return false;
	}
	if (m_sName.empty()) {
		m_editName->SetFocus();
		return false;
	}
	wxString filename = m_fpFile->GetPath();
	if (filename.empty()) {
		m_fpFile->SetFocus();
		return false;
	}
	pm::Project project;
	pm::get_by_id(1, project);
	project.name(m_sName);
	pm::update(project);
	return true;
}

////////////////////////////////////////////////////////////////////////////////
// WizardPageWorkRequest
////////////////////////////////////////////////////////////////////////////////

WizardPageWorkRequest::WizardPageWorkRequest(wxWindow* parent)
: WizardPageWorkRequestGui(parent)
{
}

double WizardPageWorkRequest::GetAmount() const
{
	double amount = 0.0;
	m_sAmount.ToDouble(&amount);
	return amount;
}

bool WizardPageWorkRequest::TransferDataFromWindow()
{
	wxLogMessage(wxT("WizardPageWorkRequest::TransferDataFromWindow()"));
	if (wxPanel::TransferDataFromWindow() == false) {
		return false;
	}
	if (GetWRName().empty()) {
		m_editName->SetFocus();
		return false;
	}
	if (m_sAmount.empty()) {
		m_editAmount->SetFocus();
		return false;
	}
	
	double amount;
	m_sAmount.ToDouble(&amount);
	
	// Insert work request
	pm::WorkRequest wr;
	pm::get_by_id(1, wr);
	wr.amount(amount);
	wr.name(GetWRName());
	wr.date(m_dpDate->GetValue());
	pm::update(wr);
	
	return true;
}

////////////////////////////////////////////////////////////////////////////////
// WizardPageTasks
////////////////////////////////////////////////////////////////////////////////

WizardPageTasks::WizardPageTasks(wxWindow* parent)
: WizardPageTasksGui(parent)
{
	m_listTask->InsertColumn(COL_NAME,      _("Name"));
	m_listTask->InsertColumn(COL_UNIT_COST, _("Unit cost"));
	m_listTask->InsertColumn(COL_QUANTITY,  _("Quantity"));
	m_listTask->InsertColumn(COL_COST,      _("Cost"));
	m_listTask->InsertColumn(COL_DATE,      _("End date"));
}

WizardPageTasks::~WizardPageTasks()
{
	for (int i = 0; i < m_listTask->GetItemCount(); ++i) {
		delete GetTask(i);
	}
}

void WizardPageTasks::GetTasks(pm::ListTask& tasks)
{
	for (int i = 0; i < m_listTask->GetItemCount(); ++i) {
		tasks.push_back(*GetTask(i));
	}
}

pm::Task* WizardPageTasks::GetTask(long item)
{
	return (pm::Task*) m_listTask->GetItemData(item);
}

void WizardPageTasks::AddTask(const pm::Task& task)
{
	long item = m_listTask->InsertItem(m_listTask->GetItemCount(), wxEmptyString);
	SetTask(item, task);
}

void WizardPageTasks::SetTask(long item, const pm::Task& task)
{
	m_listTask->SetItem(item, COL_NAME,      task.name());
	m_listTask->SetItem(item, COL_UNIT_COST, wxString::Format(wxT("%.2f"), task.unit_cost()));
	m_listTask->SetItem(item, COL_QUANTITY,  wxString::Format(wxT("%.2f"), task.quantity()));
	m_listTask->SetItem(item, COL_COST,      wxString::Format(wxT("%.2f"), task.cost()));
	m_listTask->SetItem(item, COL_DATE,      task.end_date().FormatISODate());
	
	pm::Task* pTask = GetTask(item);
	if (pTask) {
		delete pTask;
	}
	m_listTask->SetItemPtrData(item, (wxUIntPtr) new pm::Task(task));
}

bool WizardPageTasks::TransferDataFromWindow()
{
	wxLogMessage(wxT("WizardPageTasks::TransferDataFromWindow()"));
	if (wxPanel::TransferDataFromWindow() == false) {
		return false;
	}
	if (m_listTask->GetItemCount() == 0) {
		return false;
	}
	return true;
}

void WizardPageTasks::OnBtnAdd( wxCommandEvent& WXUNUSED(event) )
{
	DlgNewTask dlg(this, true);
	if (dlg.ShowModal() == wxID_OK) {
		AddTask(dlg.GetTask());
	}
}

void WizardPageTasks::OnBtnDel( wxCommandEvent& WXUNUSED(event) )
{
	long item = m_listTask->GetNextItem(-1, wxLIST_NEXT_ALL, wxLIST_STATE_SELECTED);
	if (item == wxNOT_FOUND)
		return;
	delete GetTask(item);
	m_listTask->DeleteItem(item);
}

void WizardPageTasks::OnBtnEdit( wxCommandEvent& WXUNUSED(event) )
{
	long item = m_listTask->GetNextItem(-1, wxLIST_NEXT_ALL, wxLIST_STATE_SELECTED);
	if (item == wxNOT_FOUND)
		return;
	pm::Task* pTask = GetTask(item);
	
	DlgUpdateTask dlg(this, *pTask);
	if (dlg.ShowModal() == wxID_OK) {
		SetTask(item, dlg.GetTask());
	}
}

////////////////////////////////////////////////////////////////////////////////
// WizardPageTags
////////////////////////////////////////////////////////////////////////////////

WizardPageTags::WizardPageTags(wxWindow* parent)
: WizardPageTagsGui(parent)
{
	m_listTag->InsertColumn(COL_NAME,   _("Name"));
	m_listTag->InsertColumn(COL_COLOUR, _("Colour"));
}

WizardPageTags::~WizardPageTags()
{
	for (int i = 0; i < m_listTag->GetItemCount(); ++i) {
		delete GetTag(i);
	}
}

void WizardPageTags::GetTags(pm::ListTag& tags)
{
	for (int i = 0; i < m_listTag->GetItemCount(); ++i) {
		tags.push_back(*GetTag(i));
	}
}

pm::Tag* WizardPageTags::GetTag(long item)
{
	return (pm::Tag*) m_listTag->GetItemData(item);
}

void WizardPageTags::AddTag(const pm::Tag& tag)
{
	long item = m_listTag->InsertItem(m_listTag->GetItemCount(), wxEmptyString);
	SetTag(item, tag);
}

void WizardPageTags::SetTag(long item, const pm::Tag& tag)
{
	m_listTag->SetItem(item, COL_NAME,   tag.name());
	m_listTag->SetItem(item, COL_COLOUR, tag.colour().GetAsString(wxC2S_HTML_SYNTAX));
	
	pm::Tag* pTag = GetTag(item);
	if (pTag) {
		delete pTag;
	}
	m_listTag->SetItemPtrData(item, (wxUIntPtr) new pm::Tag(tag));
}

bool WizardPageTags::TransferDataFromWindow()
{
	wxLogMessage(wxT("WizardPageTasks::TransferDataFromWindow()"));
	if (wxPanel::TransferDataFromWindow() == false) {
		return false;
	}
	if (m_listTag->GetItemCount() == 0) {
		return false;
	}
	return true;
}

void WizardPageTags::OnBtnAdd( wxCommandEvent& WXUNUSED(event) )
{
	DlgNewTag dlg(this);
	if (dlg.ShowModal() == wxID_OK) {
		AddTag(dlg.GetTag());
	}
}

void WizardPageTags::OnBtnDel( wxCommandEvent& WXUNUSED(event) )
{
	long item = m_listTag->GetNextItem(-1, wxLIST_NEXT_ALL, wxLIST_STATE_SELECTED);
	if (item == wxNOT_FOUND)
		return;
	delete GetTag(item);
	m_listTag->DeleteItem(item);
}

void WizardPageTags::OnBtnEdit( wxCommandEvent& WXUNUSED(event) )
{
	long item = m_listTag->GetNextItem(-1, wxLIST_NEXT_ALL, wxLIST_STATE_SELECTED);
	if (item == wxNOT_FOUND)
		return;
	pm::Tag* pTag = GetTag(item);
	
	DlgUpdateTag dlg(this, *pTag);
	if (dlg.ShowModal() == wxID_OK) {
		SetTag(item, dlg.GetTag());
	}
}
